#include "Epaper0213.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifndef NULL
#define NULL 0
#endif
/************************************************************************************
* 墨水屏驱动库
* 平台：MSP430G2553
* 屏幕:HINK-E0213A04-G01(汉硕Hanshow Stellar-M价签)
* BY：Laomao(https://blog.yejiah.com)
*************************************************************************************/

static char String[256];
//CS	- P3.4						//片选
//SDI	- P2.4						//SPI数据
//SCLK	- P2.3						//SPI时钟
//BUSY	- P2.5						//忙状态输出引脚
//D/C	- P3.5						//数据/命令控制引脚
//BS	- P3.1						//总线切换
//nc	- P3.7						//微雪说悬空就行 价签上接了mcu
//P2.6 = H power off；L = power on	//供电控制

//全刷寄存器
const uint8 EPD_2IN13_lut_full_update[] = {
	0x22, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x11,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E,
	0x01, 0x00, 0x00, 0x00, 0x00, 0x00
};
//局刷寄存器
const uint8 EPD_2IN13_lut_partial_update[] = {
	0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x0F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const uint8 hs_lut[] = {
	0x66,0x66,0x26,0x04,0x55,0xaa,0x08,0x91,0x11,
	0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0x19,
	0x0a,0x0a,0x5e,0x1e,0x1e,0x0a,0x39,0x14,0x00,
	0x00,0x00,0x02, };
static void Delay(unsigned int nCount)
{

	for (;nCount != 0;nCount--)
	{
		asm("nop");
		asm("nop");
		asm("nop");
		asm("nop");
	}
}
static void Delaylong(unsigned int n10Count)
{
	uint8 i;
	while (n10Count--)
	{
		for (i = 0; i < 10; i++)
		{
			Delay(10000);
		}
	}
}
//模拟软件SPI
static void SendByte_softSPI(uint8 sdbyte)
{
	volatile unsigned int i;
	for (i = 0; i < 8;i++)
	{
		EPD_SCLK_L;
		if (sdbyte & 0x80)
		{
			EPD_SDI_H;
		}
		else
		{
			EPD_SDI_L;
		}
		sdbyte <<= 1;
		EPD_SCLK_H;
	}
	EPD_SCLK_L;
}
//墨水屏发送命令
static void EPD_2IN13_SendCommand(uint8 cmd)
{
	EPD_DC_L;
	EPD_CS_L;
	SendByte_softSPI(cmd);
	EPD_CS_H;
	EPD_DC_H;
}
//墨水屏发送数据
static void EPD_2IN13_SendData(uint8 data)
{
	EPD_DC_H;
	EPD_CS_L;
	SendByte_softSPI(data);
	EPD_CS_H;
}
static void EPD_2IN13_SendData_Multi(const uint8* data, uint16 data_size)
{
	EPD_DC_H;
	EPD_CS_L;
	while (data_size)
	{
		SendByte_softSPI(*data++);
		data_size--;
	}
	EPD_CS_H;
}
static void EPD_2IN13_SendCmdData(uint8 cmd, uint8 data)
{
	EPD_DC_L;
	EPD_CS_L;
	SendByte_softSPI(cmd);
	EPD_DC_H;
	SendByte_softSPI(data);
	EPD_CS_H;
}

static void EPD_2IN13_Reset(void)
{
	//DEV_Digital_Write(EPD_RST_PIN, 1);
	//DEV_Delay_ms(200);
	//DEV_Digital_Write(EPD_RST_PIN, 0);
	//DEV_Delay_ms(2);
	//DEV_Digital_Write(EPD_RST_PIN, 1);
	//DEV_Delay_ms(200);
	Delaylong(3);
	EPD_RST_H;
	Delaylong(3);
	EPD_RST_L;
	Delaylong(3);
	EPD_RST_H;
	Delaylong(3);

}
static void EPD_2IN13_ReadBusy(void)
{
	while ((P2IN & BIT5) == 1) {      //LOW: idle, HIGH: busy
		Delaylong(2);
	}
}
void SetLut(const uint8* lut) {
	EPD_2IN13_SendCommand(WRITE_LUT_REGISTER);
	/* 查询表的长度为30个字节 */
	for (int i = 0; i < 30; i++) {
		EPD_2IN13_SendData(lut[i]);
	}
}
static void EPD_2IN13urnOnDisplay(void)
{
	EPD_2IN13_SendCommand(DISPLAY_UPDATE_CONTROL_2);	//显示更新控制2
	EPD_2IN13_SendData(0xC7);							//微雪是C4 汉硕C7
	EPD_2IN13_SendCommand(MASTER_ACTIVATION);			// 主激活
	EPD_2IN13_SendCommand(TERMINATE_FRAME_READ_WRITE);	// 终止帧读写
	EPD_2IN13_ReadBusy();
	Delaylong(100);
}
/**
 * @brief  设置EPD显示窗口位置和大小。
 * @param  x 显示窗口起始X位置。
 * @param  y_x8 显示窗口起始Y位置，设置1等于8像素。
 * @param  x_size 显示窗口X方向大小。
 * @param  y_size_x8 显示窗口Y方向大小，设置1等于8像素。
 * @note   指针已被自动设置至窗口的左上角。
 */
void EPD_SetWindow(uint16 x, uint8 y_x8, uint16 x_size, uint8 y_size_x8)
{
	x = EPD_2IN13_HEIGHT - 1 - x;
	x_size = x - x_size + 1;          /* x_size已变为x结束地址 */
	y_size_x8 = y_size_x8 + y_x8 - 1; /* y_size已变为y结束地址 */

	EPD_2IN13_SendCommand(SET_RAM_X_ADDRESS_START_END_POSITION); /* 设置X（短边）起始地址和结束地址，根据扫描方式不同，地址设置也不同 */
	EPD_2IN13_SendData(y_x8);
	EPD_2IN13_SendData(y_size_x8 & 0x1F);
	EPD_2IN13_SendCommand(SET_RAM_Y_ADDRESS_START_END_POSITION); /* 设置Y（长边）起始地址和结束地址，根据扫描方式不同，地址设置也不同 */
	EPD_2IN13_SendData(x & 0xFF);
	EPD_2IN13_SendData((x >> 8) & 0x01);
	EPD_2IN13_SendData(x_size & 0xFF);
	EPD_2IN13_SendData((x_size >> 8) & 0x01);

	EPD_2IN13_SendCommand(SET_RAM_X_ADDRESS_COUNTER); /* 设置X（短边）地址计数器 */
	EPD_2IN13_SendData(y_x8);
	EPD_2IN13_SendCommand(SET_RAM_Y_ADDRESS_COUNTER); /* 设置Y（长边）地址计数器 */
	EPD_2IN13_SendData(x & 0xFF);
	EPD_2IN13_SendData((x >> 8) & 0x01);
}
static void EPD_2IN13_SetWindows(int x_start, int y_start, int x_end, int y_end)
{
	EPD_2IN13_SendCommand(SET_RAM_X_ADDRESS_START_END_POSITION);
	/* x点必须是8的倍数，否则后3位将被忽略 */
	EPD_2IN13_SendData((x_start >> 3) & 0xFF);
	EPD_2IN13_SendData((x_end >> 3) & 0xFF);
	EPD_2IN13_SendCommand(SET_RAM_Y_ADDRESS_START_END_POSITION);
	EPD_2IN13_SendData(y_start & 0xFF);
	EPD_2IN13_SendData((y_start >> 8) & 0xFF);
	EPD_2IN13_SendData(y_end & 0xFF);
	EPD_2IN13_SendData((y_end >> 8) & 0xFF);
}
/**
 * @brief  设置EPD显示数据指针位置。
 * @param  x 显示数据指针起始X位置。
 * @param  y_x8 显示数据指针起始Y位置，设置1等于8像素。
 */
static void EPD_2IN13_SetCursor(int x, int y)
{
	EPD_2IN13_SendCommand(SET_RAM_X_ADDRESS_COUNTER);/* 设置X（短边）地址计数器 */
	/* x point must be the multiple of 8 or the last 3 bits will be ignored */
	EPD_2IN13_SendData((x >> 3) & 0xFF);
	EPD_2IN13_SendCommand(SET_RAM_Y_ADDRESS_COUNTER);/* 设置Y（长边）地址计数器 */
	EPD_2IN13_SendData(y & 0xFF);
	EPD_2IN13_SendData((y >> 8) & 0xFF);
	//    EPD_2IN13_ReadBusy();
}
void EPD_2IN13_DeepSleep(void)
{
	EPD_2IN13_SendCommand(DISPLAY_UPDATE_CONTROL_2);	//显示更新控制2
	EPD_2IN13_SendData(0x03);							//微雪是C4 汉硕C7
	EPD_2IN13_SendCommand(MASTER_ACTIVATION);			// 主激活
	EPD_2IN13_ReadBusy();
	EPD_2IN13_SendCommand(DEEP_SLEEP_MODE); //DEEP_SLEEP_MODE
	EPD_2IN13_SendData(0x01);
}
/**
 * @brief  清除EPD控制器内全部显示RAM。
 * @note   上次数据都不要就要先清屏 不然会由于寄存器没数据造成花屏或者残影
 */
void EPD_ClearRAM(void)
{
	uint8 Width = 0, Height = 0;
	Width = (EPD_2IN13_WIDTH % 8 == 0) ? (EPD_2IN13_WIDTH / 8) : (EPD_2IN13_WIDTH / 8 + 1);
	Height = EPD_2IN13_HEIGHT;

	EPD_2IN13_SetWindows(0, 0, EPD_2IN13_WIDTH, EPD_2IN13_HEIGHT);
	for (uint8 j = 0; j < Height; j++) {
		EPD_2IN13_SetCursor(0, j);
		EPD_2IN13_SendCommand(WRITE_RAM);
		for (uint8 i = 0; i < Width; i++) {
			EPD_2IN13_SendData(0xFF);
		}
	}
}
/**
 * @brief  向EPD控制器发送指定大小的显示数据。
 * @param  data 要发送数据的指针。
 * @param  data_size 要发送数据的大小。
 */
void EPD_SendRAM(const uint8* data, uint16 data_size)
{
	EPD_2IN13_SendCommand(WRITE_RAM);
	EPD_2IN13_SendData_Multi(data, data_size);
}
//全屏填充
void EPD_2IN13_Fill(uint8 color)
{
	uint8 Width = 0, Height = 0;
	Width = (EPD_2IN13_WIDTH % 8 == 0) ? (EPD_2IN13_WIDTH / 8) : (EPD_2IN13_WIDTH / 8 + 1);
	Height = EPD_2IN13_HEIGHT;

	EPD_2IN13_SetWindows(0, 0, EPD_2IN13_WIDTH, EPD_2IN13_HEIGHT);
	for (uint8 j = 0; j < Height; j++) {
		EPD_2IN13_SetCursor(0, j);
		EPD_2IN13_SendCommand(WRITE_RAM);
		for (uint8 i = 0; i < Width; i++) {
			EPD_2IN13_SendData(color);
		}
	}

	EPD_2IN13urnOnDisplay();
}
/**
 * @brief  清除EPD控制器指定区域显示RAM。
 * @note   执行完成后窗口会恢复至全屏幕。
 */
void EPD_ClearArea(uint16 x, uint8 y_x8, uint16 x_size, uint8 y_size_x8, uint8 color)
{
	uint16 i, data_size;

	data_size = x_size * y_size_x8;
	EPD_SetWindow(x, y_x8, x_size, y_size_x8);
	EPD_2IN13_SendCommand(WRITE_RAM);
	for (i = 0; i < data_size; i++)
	{
		EPD_2IN13_SendData(color);
	}
	EPD_SetWindow(0, 0, 250, 16);
}
void EPD_2IN13_Display(const uint8* Image)
{
	uint8 Width, Height;
	Width = (EPD_2IN13_WIDTH % 8 == 0) ? (EPD_2IN13_WIDTH / 8) : (EPD_2IN13_WIDTH / 8 + 1);
	Height = EPD_2IN13_HEIGHT;

	EPD_2IN13_SetWindows(0, 0, EPD_2IN13_WIDTH, EPD_2IN13_HEIGHT);
	for (uint8 j = 0; j < Height; j++) {
		EPD_2IN13_SetCursor(0, j);
		EPD_2IN13_SendCommand(WRITE_RAM);
		for (uint8 i = 0; i < Width; i++) {
			EPD_2IN13_SendData(Image[i + j * Width]);
		}
	}
	EPD_2IN13urnOnDisplay();
}
void EPD_2IN13_Init(void)
{

	EPD_NC_H;
	EPD_BS_L;//BS：VCC: 3线SPI / GND: 4线SPI
	EPD_ON;

	P2DIR &= ~BIT5;								//P2.5设置为输入
	P2DIR |= BIT3 | BIT4 | BIT6;
	P3DIR |= BIT1 | BIT4 | BIT5 | BIT6 | BIT7;

	P1SEL = 0X0;
	P1SEL2 = 0X0;
	P2SEL = 0X0;
	P2SEL2 = 0X0;
	P3SEL = 0X0;
	P3SEL2 = 0X0;

	EPD_2IN13_Reset();
	EPD_2IN13_SendCommand(DRIVER_OUTPUT_CONTROL); // DRIVER_OUTPUT_CONTROL
	EPD_2IN13_SendData((EPD_2IN13_HEIGHT - 1) & 0xFF);
	EPD_2IN13_SendData(((EPD_2IN13_HEIGHT - 1) >> 8) & 0xFF);
	EPD_2IN13_SendData(0x00);			// GD = 0; SM = 0; TB = 0;

	EPD_2IN13_SendCommand(BOOSTER_SOFT_START_CONTROL);	// BOOSTER_SOFT_START_CONTROL
	EPD_2IN13_SendData(0xD7);
	EPD_2IN13_SendData(0xD6);
	EPD_2IN13_SendData(0x9D);

	EPD_2IN13_SendCommand(WRITE_VCOM_REGISTER);	// WRITE_VCOM_REGISTER
	EPD_2IN13_SendData(0xA8);     // VCOM 7C

	EPD_2IN13_SendCommand(SET_DUMMY_LINE_PERIOD);	// SET_DUMMY_LINE_PERIOD
	EPD_2IN13_SendData(0x1A);			// 4 dummy lines per gate

	EPD_2IN13_SendCommand(SET_GATE_TIME);	// SET_GATEIME
	EPD_2IN13_SendData(0x08);			// 2us per line

	EPD_2IN13_SendCommand(BORDER_WAVEFORM_CONTROL);	// BORDER_WAVEFORM_CONTROL
	EPD_2IN13_SendData(0x03);

	EPD_2IN13_SendCommand(DATA_ENTRY_MODE_SETTING);	// DATA_ENTRY_MODE_SETTING
	EPD_2IN13_SendData(0x03);			// X increment; Y increment

	SetLut(&hs_lut[0]);
}
void EPD_2IN13_Denit(void)
{
	EPD_2IN13_SendCmdData(0x10, 0x01);
	Delay(10);

	EPD_OFF;

	// reset pin direction to input
	// p2.5 is busy pin
	P2DIR &= ~(BIT3 | BIT4 | BIT6);
	P3DIR &= ~(BIT1 | BIT4 | BIT5 | BIT6 | BIT7);
}

/**
 * @brief  绘制水平直线。
 * @param  x 绘制起始X位置。
 * @param  y 绘制起始Y位置。
 * @param  x_size 绘制长度。
 * @param  width 线宽度。
 * @note   Y方向始终会占用8的倍数的像素，例如在0,0位置绘制一条1像素宽高的线，会清除Y方向8像素内的显示数据。
 */
void EPD_DrawHLine(uint16 x, uint8 y, uint16 x_size, uint8 width)
{
	uint16 i;
	uint8 j, k, block, height, yemp, widthemp;

	height = (y % 8 + width - 1) / 8 + 1;
	EPD_SetWindow(x, y / 8, x_size, height);
	for (i = 0; i < x_size; i++)
	{
		yemp = y;
		widthemp = width;
		for (j = 0; j < height; j++)
		{
			block = 0x00;
			for (k = (yemp % 8); k < 8; k++)
			{
				block |= 0x80 >> k;
				widthemp -= 1;
				if (widthemp <= 0)
				{
					break;
				}
			}
			yemp = 0;
			block = ~block;
			EPD_SendRAM((uint8*)&block, 1);
		}
	}
}

/**
 * @brief  绘制垂直直线。
 * @param  x 绘制起始X位置。
 * @param  y 绘制起始Y位置。
 * @param  y_size 绘制长度。
 * @param  width 线宽度。
 * @note   Y方向始终会占用8的倍数的像素，例如在0,0位置绘制一条1像素宽高的线，会清除Y方向8像素内的显示数据。
 */
void EPD_DrawVLine(uint16 x, uint8 y, uint8 y_size, uint16 width)
{
	uint16 i;
	uint8 j, k, block, height, yemp, widthemp;

	height = (y % 8 + y_size - 1) / 8 + 1;
	EPD_SetWindow(x, y / 8, width, height);
	for (i = 0; i < width; i++)
	{
		yemp = y;
		widthemp = y_size;
		for (j = 0; j < height; j++)
		{
			block = 0x00;
			for (k = (yemp % 8); k < 8; k++)
			{
				block |= 0x80 >> k;
				widthemp -= 1;
				if (widthemp <= 0)
				{
					break;
				}
			}
			yemp = 0;
			block = ~block;
			EPD_SendRAM((uint8*)&block, 1);
		}
	}
}

/**
 * @brief  绘制UTF8字符串。
 * @param  x 绘制起始X位置。
 * @param  y_x8 绘制起始Y位置，设置1等于8像素。
 * @param  gap 字符间额外间距。
 * @param  str 要绘制的字符串指针。
 * @param  ascii_font ASCII字符字模指针。
 * @param  utf8_font UTF8字符字模指针。
 * @note   调用的文件必须是utf-8编码 否则中文会错误
 */
#define Interval_Ascii_Utf8 10			//ASCII字符与UTF8的间隔
void EPD_DrawFonts(uint16 x, uint8 y_x8, uint8 gap, const char* str, const epdFONT_ascii* ascii_font, const epdFONT_utf8* utf8_font)
{

	uint8 i = 0, utf8_size = 0;
	uint16 x_count = 0, font_size = 0;
	const uint8* ascii_base_addr = NULL;
	uint32 unicode = 0, unicodeemp = 0;

	x_count = 0;
	while (*str != '\0')
	{
		if ((*str & 0x80) == 0x00) /* 普通ASCII字符 */
		{
			if (ascii_font != NULL)
			{
				font_size = ascii_font->Width * ascii_font->Hight / 8;
				ascii_base_addr = ascii_font->fp + (*str - ascii_font->StartChar) * font_size;
				if (ascii_base_addr + font_size <= ascii_font->fp + font_size * ascii_font->num) /* 限制数组范围 */
				{
					EPD_SetWindow(x + x_count, y_x8, ascii_font->Width, ascii_font->Hight / 8);
					EPD_SendRAM(ascii_base_addr, font_size);
				}
				x_count += ascii_font->Width + gap;
			}
			else if (*str == ' ' && utf8_font != NULL) /* 未指定ASCII字体时空格为UTF8字体宽度除2 */
			{
				font_size = (utf8_font->Width / 2) * (utf8_font->Hight / 8);
				EPD_SetWindow(x + x_count, y_x8, utf8_font->Width / 2, utf8_font->Hight / 8);
				for (i = 0; i < font_size; i++)
				{
					utf8_size = 0xFF; /* 借用变量 */
					EPD_SendRAM(&utf8_size, 1);
				}
				x_count += utf8_font->Width / 2 + gap;
			}
		}
		else if (utf8_font != NULL) /* UTF8字符 */
		{
			unicode = 0x000000;
			utf8_size = 0;
			for (i = 0; i < 5; i++)
			{
				if (*str & (0x80 >> i))
				{
					utf8_size += 1;
				}
				else
				{
					break;
				}
			}
			switch (utf8_size)
			{
			case 2:
				if (*(str + 1) != '\0')
				{
					unicode = ((uint32)(*str & 0x1F)) << 6;
					str += 1;
					unicode |= (uint32)*str & 0x3F;
				}
				break;
			case 3:
				if (*(str + 1) != '\0' && *(str + 2) != '\0')
				{
					unicode = ((uint32)(*str & 0x0F)) << 12;
					str += 1;
					unicode |= ((uint32)(*str & 0x3F)) << 6;
					str += 1;
					unicode |= (uint32)*str & 0x3F;
				}
				break;
			case 4:
				if (*(str + 1) != '\0' && *(str + 2) != '\0' && *(str + 3) != '\0')
				{
					unicode = ((uint32)(*str & 0x07)) << 18;
					str += 1;
					unicode |= ((uint32)(*str & 0x3F)) << 12;
					str += 1;
					unicode |= ((uint32)(*str & 0x3F)) << 6;
					str += 1;
					unicode |= (uint32)*str & 0x3F;
				}
				break;
			}
			if (unicode != 0)
			{
				font_size = utf8_font->Width * utf8_font->Hight / 8;
				for (i = 0; i < utf8_font->num; i++) /* 限制数组范围 */
				{
					unicodeemp = (uint32)utf8_font->fp[0 + (font_size + 3) * i] << 16;
					unicodeemp |= (uint32)utf8_font->fp[1 + (font_size + 3) * i] << 8;
					unicodeemp |= (uint32)utf8_font->fp[2 + (font_size + 3) * i];
					if (unicodeemp == unicode)
					{
						EPD_SetWindow(x + x_count + Interval_Ascii_Utf8, y_x8, utf8_font->Width, utf8_font->Hight / 8);
						EPD_SendRAM(utf8_font->fp + 3 + (font_size + 3) * i, font_size);
						break;
					}
				}
			}
			x_count += utf8_font->Width + gap;
		}
		str += 1;
	}
}
extern const uint8 jmu[];
extern const uint8 test[];

void epd_distest(void) {
	//EPD_2IN13_Fill();
	EPD_ClearRAM();

	EPD_DrawHLine(248, 28, 250, 2);		//画水平线是从右往左
	EPD_DrawHLine(248, 104, 250, 2);	//画水平线是从右往左
	EPD_DrawHLine(238, 67, 60, 2);		//画水平线是从右往左
	EPD_DrawVLine(170, 39, 56, 2);		//画垂直分割线

	//顶栏
	snprintf(String, sizeof(String), "2%03d年%02d月%02d日 星期%s", 88, 8, 8,"日");
	EPD_DrawFonts(10, 0, 0, String, &Ascii_YouYuan_12x24, &utf8_CN_24x24);

	//底栏
	//EPD_DrawFonts(10, 14, 0, "Chengyi University College", &Ascii_YouYuan_8x16, NULL);

	//主时钟
	snprintf(String, sizeof(String), "%02d:%02d", 8, 8);
	EPD_DrawFonts(40, 5, 2, String, &Ascii_DigitalDismay_28x56, NULL);

	//温度
	snprintf(String, sizeof(String), "%02d.%d℃", 88, 8);
	EPD_DrawFonts(188, 5, 0, String, &Ascii_YouYuan_12x24, &utf8_CN_24x24);

	//湿度
	snprintf(String, sizeof(String), "%02d.%d％", 88, 8);
	EPD_DrawFonts(188, 9, 0, String, &Ascii_YouYuan_12x24, &utf8_CN_24x24);



	EPD_2IN13urnOnDisplay();
	EPD_2IN13_SendCmdData(0x10, 0x01);

}



